// **************************************************************
// COPYRIGHT(c)2020, Xidian University
// All rights reserved.
//
// IP LIB INDEX :  
// IP Name      :      
// File name    : cross_clumn_select.v
// Module name  : cross_clumn_select
// Full name    :  
//
// Author       : Hbing
// Email        : 2629029232@qq.com
// Data         : 2020/9/12
// Version      : V 1.0 
// 
// Abstract     : 
// Called by    :  
// 
// Modification history
// -----------------------------------------------------------------
// 
// 
// 
// *****************************************************************
// `include "top_define.v"
// *******************
// TIMESCALE
// ******************* 
`timescale 1ns/1ps 

// *******************
// DESCRIPTION
// *******************
// 3*3交叉节点，但是为了防止阻塞，第三列交叉节点中的乒乓RAM翻倍，分别存port2,port3目的端口的数据帧
// 改成4*4 增加一路轮询
// 
//*******************
//DEFINE(s)
//*******************
//`define UDLY 1    //Unit delay, for non-blocking assignments in sequential logic

//*******************
//DEFINE MODULE PORT
//*******************
module cross_clumn_select(
    //sysrem input/output
    input  wire         clk                ,
    input  wire         rst_n              ,
    //同一列选择
    input  wire [255:0] emac_data_final0   ,
    input  wire         emac_dval_final0   ,
    input  wire         emac_dsav_final0   ,
    input  wire         emac_sop_final0    ,
    input  wire         emac_eop_final0    ,
    input  wire [  4:0] emac_mod_final0    ,
    input  wire         mac_dest_port_en0  ,
    input  wire         uni_in_busy0       ,
    input  wire         mul_in_busy0       ,
    output reg          out_enable0        ,
    input  wire [ 10:0] emac_len_final0    ,
    //input  wire [  2:0] emac_pri_final0    ,
    input  wire          read_finish0       ,

    input  wire [255:0] emac_data_final1   ,
    input  wire         emac_dval_final1   ,
    input  wire         emac_dsav_final1   ,
    input  wire         emac_sop_final1    ,
    input  wire         emac_eop_final1    ,
    input  wire [  4:0] emac_mod_final1    ,
    input  wire         mac_dest_port_en1  ,
    input  wire         uni_in_busy1       ,
    input  wire         mul_in_busy1       ,
    output reg          out_enable1        ,
    input  wire [ 10:0] emac_len_final1    ,
    //input  wire [  2:0] emac_pri_final1    ,
    input  wire          read_finish1       ,

    input  wire [255:0] emac_data_final2   ,
    input  wire         emac_dval_final2   ,
    input  wire         emac_dsav_final2   ,
    input  wire         emac_sop_final2    ,
    input  wire         emac_eop_final2    ,
    input  wire [  4:0] emac_mod_final2    ,
    input  wire         mac_dest_port_en2  ,
    input  wire         uni_in_busy2       ,
    input  wire         mul_in_busy2       ,
    output reg          out_enable2        ,
    input  wire [ 10:0] emac_len_final2    ,
    //input  wire [  2:0] emac_pri_final2    ,
    input  wire          read_finish2       ,

    input  wire [255:0] emac_data_final3   ,
    input  wire         emac_dval_final3   ,
    input  wire         emac_dsav_final3   ,
    input  wire         emac_sop_final3    ,
    input  wire         emac_eop_final3    ,
    input  wire [  4:0] emac_mod_final3    ,
    input  wire         mac_dest_port_en3  ,
    input  wire         uni_in_busy3       ,
    input  wire         mul_in_busy3       ,
    output reg          out_enable3        ,
    input  wire [ 10:0] emac_len_final3    ,
    //input  wire [  2:0] emac_pri_final3    ,
    input  wire          read_finish3       ,
    //输出数据
    output reg  [255:0] emac_data_final    ,
    output reg          emac_dval_final    ,
    output reg          emac_dsav_final    ,
    output reg          emac_sop_final     ,
    output reg          emac_eop_final     ,
    output reg  [  4:0] emac_mod_final     ,
    output reg  [ 10:0] emac_len_final     
);
//*******************
//DEFINE LOCAL PARAMETER
//*******************
//parameter(s)
localparam IDLE   = 4'b0000;
localparam FIRST  = 4'b0001;
localparam SECOND = 4'b0010;
localparam THIRD  = 4'b0100;
localparam FOUR   = 4'b1000;
integer TX_DATA;
//交叉节点乒乓RAM写入w256-d64
//6'b000000--队列号-帧长-目的端口列表
//6'b000001--SRAM_memory读出的数据
//*********************
//INNER SIGNAL DECLARATION
//*********************
//REGS
//状态机
reg [3:0] c_state,n_state;
//寄存上一次发送的行数
reg [1:0] last_point;
//等待状态维持时间--是否必要？
//reg [2:0] wait_step;
//不同行优先级比较
// reg pri_0_max;
// reg pri_1_max;
// reg pri_2_max;

//输出使能延迟2拍
reg out_enable0_d1;
reg out_enable1_d1;
reg out_enable2_d1;
reg out_enable3_d1;
reg out_enable0_d2;
reg out_enable1_d2;
reg out_enable2_d2;
reg out_enable3_d2;
//WIRES
//*********************
//INSTANTCE MODULE
//*********************


//*********************
//MAIN CORE
//********************* 
//状态机
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        c_state <= IDLE;
    end
    else begin
        c_state <= n_state;
    end
end

always @(*) begin
case(c_state)
    IDLE:
    begin
    case(last_point)
        2'b00: begin
            if (mul_in_busy1 == 1'b1) begin
                n_state = SECOND;
            end
            else if (mul_in_busy2 == 1'b1) begin
                n_state = THIRD;
            end
            else if (mul_in_busy3 == 1'b1) begin
                n_state = FOUR;
            end
            else if (mul_in_busy0 == 1'b1) begin
                n_state = FIRST;
            end
            else if (uni_in_busy1 == 1'b1) begin
                n_state = SECOND;
            end
            else if (uni_in_busy2 == 1'b1) begin
                n_state = THIRD;
            end
            else if (uni_in_busy3 == 1'b1) begin
                n_state = FOUR;
            end
            else if (uni_in_busy0 == 1'b1) begin
                n_state = FIRST;
            end
            else begin
                n_state = IDLE;
            end
        end
        2'b01: begin
            if (mul_in_busy2 == 1'b1) begin
                n_state = THIRD;
            end
            else if (mul_in_busy3 == 1'b1) begin
                n_state = FOUR;
            end
            else if (mul_in_busy0 == 1'b1) begin
                n_state = FIRST;
            end
            else if (mul_in_busy1 == 1'b1) begin
                n_state = SECOND;
            end
            else if (uni_in_busy2 == 1'b1) begin
                n_state = THIRD;
            end
            else if (uni_in_busy3 == 1'b1) begin
                n_state = FOUR;
            end
            else if (uni_in_busy0 == 1'b1) begin
                n_state = FIRST;
            end
            else if (uni_in_busy1 == 1'b1) begin
                n_state = SECOND;
            end
            else begin
                n_state = IDLE;
            end
        end
        2'b10: begin
            if (mul_in_busy3 == 1'b1) begin
                n_state = FOUR;
            end
            else if (mul_in_busy0 == 1'b1) begin
                n_state = FIRST;
            end
            else if (mul_in_busy1 == 1'b1) begin
                n_state = SECOND;
            end
            else if (mul_in_busy2 == 1'b1) begin
                n_state = THIRD;
            end
            else if (uni_in_busy3 == 1'b1) begin
                n_state = FOUR;
            end
            else if (uni_in_busy0 == 1'b1) begin
                n_state = FIRST;
            end
            else if (uni_in_busy1 == 1'b1) begin
                n_state = SECOND;
            end
            else if (uni_in_busy2 == 1'b1) begin
                n_state = THIRD;
            end
            else begin
                n_state = IDLE;
            end
        end
        2'b11: begin
            if (mul_in_busy0 == 1'b1) begin
                n_state = FIRST;
            end
            else if (mul_in_busy1 == 1'b1) begin
                n_state = SECOND;
            end
            else if (mul_in_busy2 == 1'b1) begin
                n_state = THIRD;
            end
            else if (mul_in_busy3 == 1'b1) begin
                n_state = FOUR;
            end
            else if (uni_in_busy0 == 1'b1) begin
                n_state = FIRST;
            end
            else if (uni_in_busy1 == 1'b1) begin
                n_state = SECOND;
            end
            else if (uni_in_busy2 == 1'b1) begin
                n_state = THIRD;
            end
            else if (uni_in_busy3 == 1'b1) begin
                n_state = FOUR;
            end
            else begin
                n_state = IDLE;
            end
        end
        default: begin
            n_state = FIRST;
        end
    endcase
    end
    FIRST:
    begin
        if (read_finish0 == 1'b1) begin
            n_state = IDLE;
        end
        else begin
            n_state = FIRST;
        end
    end
    SECOND:
    begin
        if (read_finish1 == 1'b1) begin
            n_state = IDLE;
        end
        else begin
            n_state = SECOND;
        end
    end
    THIRD:
    begin
        if (read_finish2 == 1'b1) begin
            n_state = IDLE;
        end
        else begin
            n_state = THIRD;
        end
    end
    FOUR:
    begin
        if (read_finish3 == 1'b1) begin
            n_state = IDLE;
        end
        else begin
            n_state = FOUR;
        end
    end
    default:
    begin
        n_state = IDLE;
    end
endcase
end

//寄存上一次发送的行数
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        last_point <= 2'b11;
    end
    else if (c_state == FIRST) begin
        last_point <= 2'b00;
    end
    else if (c_state == SECOND) begin
        last_point <= 2'b01;
    end
    else if (c_state == THIRD) begin
        last_point <= 2'b10;
    end
    else if (c_state == FOUR) begin
        last_point <= 2'b11;
    end
    else begin
        last_point <= last_point;
    end
end
// //不同行优先级比较
// always @(posedge clk or negedge rst_n) begin
//     if (!rst_n) begin
//         pri_0_max <= 1'b0;
//     end
//     else if ((emac_pri_final0 >= emac_pri_final1) && (emac_pri_final0 >= emac_pri_final2)) begin
//         pri_0_max <= 1'b1;
//     end
//     else if ((emac_pri_final0 < emac_pri_final1) || (emac_pri_final0 < emac_pri_final2)) begin
//         pri_0_max <= 1'b0;
//     end
//     else begin
//         pri_0_max <= pri_0_max;
//     end
// end

// always @(posedge clk or negedge rst_n) begin
//     if (!rst_n) begin
//         pri_1_max <= 1'b0;
//     end
//     else if ((emac_pri_final1 >= emac_pri_final0) && (emac_pri_final1 >= emac_pri_final2)) begin
//         pri_1_max <= 1'b1;
//     end
//     else if ((emac_pri_final1 < emac_pri_final0) || (emac_pri_final1 < emac_pri_final2)) begin
//         pri_1_max <= 1'b0;
//     end
//     else begin
//         pri_1_max <= pri_1_max;
//     end
// end

// always @(posedge clk or negedge rst_n) begin
//     if (!rst_n) begin
//         pri_2_max <= 1'b0;
//     end
//     else if ((emac_pri_final2 >= emac_pri_final0) && (emac_pri_final2 >= emac_pri_final1)) begin
//         pri_2_max <= 1'b1;
//     end
//     else if ((emac_pri_final2 < emac_pri_final0) || (emac_pri_final2 < emac_pri_final1)) begin
//         pri_2_max <= 1'b0;
//     end
//     else begin
//         pri_2_max <= pri_2_max;
//     end
// end

//给交叉节点返回的输出使能，表明某个交叉节点可以发数据
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        out_enable0 <= 1'b0;
    end
    else if (n_state == FIRST) begin
        out_enable0 <= 1'b1;
    end
    else begin
        out_enable0 <= 1'b0;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        out_enable1 <= 1'b0;
    end
    else if (n_state == SECOND) begin
        out_enable1 <= 1'b1;
    end
    else begin
        out_enable1 <= 1'b0;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        out_enable2 <= 1'b0;
    end
    else if (n_state == THIRD) begin
        out_enable2 <= 1'b1;
    end
    else begin
        out_enable2 <= 1'b0;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        out_enable3 <= 1'b0;
    end
    else if (n_state == FOUR) begin
        out_enable3 <= 1'b1;
    end
    else begin
        out_enable3 <= 1'b0;
    end
end

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        out_enable0_d1 <= 1'b0;
        out_enable1_d1 <= 1'b0;
        out_enable2_d1 <= 1'b0;
        out_enable3_d1 <= 1'b0;
        out_enable0_d2 <= 1'b0;
        out_enable1_d2 <= 1'b0;
        out_enable2_d2 <= 1'b0;
        out_enable3_d2 <= 1'b0;
    end
    else begin
        out_enable0_d1 <= out_enable0;
        out_enable1_d1 <= out_enable1;
        out_enable2_d1 <= out_enable2;
        out_enable3_d1 <= out_enable3;
        out_enable0_d2 <= out_enable0_d1;
        out_enable1_d2 <= out_enable1_d1;
        out_enable2_d2 <= out_enable2_d1;
        out_enable3_d2 <= out_enable3_d1;
    end
end

//输出数据
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        emac_data_final <= 256'b0;
        emac_dval_final <= 1'b0  ;
        emac_dsav_final <= 1'b0  ;
        emac_sop_final  <= 1'b0  ;
        emac_eop_final  <= 1'b0  ;
        emac_mod_final  <= 5'b0  ;
        emac_len_final  <= 11'b0 ;
    end
    else if ((out_enable0_d2 == 1'b1) && (mac_dest_port_en0 == 1'b1)) begin
        emac_data_final <= emac_data_final0 ;
        emac_dval_final <= emac_dval_final0 ;
        emac_dsav_final <= emac_dsav_final0 ;
        emac_sop_final  <= emac_sop_final0  ;
        emac_eop_final  <= emac_eop_final0  ;
        emac_mod_final  <= emac_mod_final0  ;
        emac_len_final  <= emac_len_final0  ;
    end
    else if ((out_enable1_d2 == 1'b1) && (mac_dest_port_en1 == 1'b1)) begin
        emac_data_final <= emac_data_final1 ;
        emac_dval_final <= emac_dval_final1 ;
        emac_dsav_final <= emac_dsav_final1 ;
        emac_sop_final  <= emac_sop_final1  ;
        emac_eop_final  <= emac_eop_final1  ;
        emac_mod_final  <= emac_mod_final1  ;
        emac_len_final  <= emac_len_final1  ;
    end
    else if ((out_enable2_d2 == 1'b1) && (mac_dest_port_en2 == 1'b1)) begin
        emac_data_final <= emac_data_final2 ;
        emac_dval_final <= emac_dval_final2 ;
        emac_dsav_final <= emac_dsav_final2 ;
        emac_sop_final  <= emac_sop_final2  ;
        emac_eop_final  <= emac_eop_final2  ;
        emac_mod_final  <= emac_mod_final2  ;
        emac_len_final  <= emac_len_final2  ;
    end
    else if ((out_enable3_d2 == 1'b1) && (mac_dest_port_en3 == 1'b1)) begin
        emac_data_final <= emac_data_final3 ;
        emac_dval_final <= emac_dval_final3 ;
        emac_dsav_final <= emac_dsav_final3 ;
        emac_sop_final  <= emac_sop_final3  ;
        emac_eop_final  <= emac_eop_final3  ;
        emac_mod_final  <= emac_mod_final3  ;
        emac_len_final  <= emac_len_final3  ;
    end
    else begin
        emac_data_final <= 256'b0;
        emac_dval_final <= 1'b0  ;
        emac_dsav_final <= 1'b0  ;
        emac_sop_final  <= 1'b0  ;
        emac_eop_final  <= 1'b0  ;
        emac_mod_final  <= 5'b0  ;
        emac_len_final  <= 11'b0 ;
    end
end



endmodule
